{*******************************************************************************
* The contents of this file are used with permission, subject to the Mozilla   *
* Public License Version 1.1 (the "License"); you may not use this file except *
* in compliance with the License. You may obtain a copy of the License at      *
* http://www.mozilla.org/MPL/                                                  *
*                                                                              *
* Software distributed under the License is distributed on an "AS IS" basis,   *
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for *
* the specific language governing rights and limitations under the License.    *
*                                                                              *
* The Original Code is distributed as part of the "mediate" product and is     *
* Copyright (C) @home media limited. All Rights Reserved.                      *
*                                                                              *
* Email: support@athomemedia.co.uk                                             *
* Web:   http://www.athomemedia.co.uk                                          *
*******************************************************************************}

unit Persistence;

interface

uses Classes, MetaValues, XMLHelper;

const
  STATE_FILENAME = 'ApplicationState.xml';

  // Default values for application state
  DEF_MEDIA_VOLUME = 0;
  DEF_MEDIA_MUTING = False;


type
  TAHMPersistenceManager = class
  private
    FPrimaryFolder: WideString;
    FPrimaryFile: WideString;
    FSecondaryFolder: WideString;
    FSecondaryFile: WideString;
    FMediaVolume: Integer;
    FMediaMuting: Boolean;
    FMetaSettings: TAHMMetaValueList;
    FHelper: TAHMXMLHelper;
  protected
    function ParseXML(const Filepath: String): Boolean;
    procedure LogParsingError(const sErrorCode: String);
  public
    constructor Create;
    destructor Destroy; override;
    property PrimaryMediaFolder: WideString read FPrimaryFolder write FPrimaryFolder;
    property PrimaryMediaFile: WideString read FPrimaryFile write FPrimaryFile;
    property SecondaryMediaFolder: WideString read FSecondaryFolder write FSecondaryFolder;
    property SecondaryMediaFile: WideString read FSecondaryFile write FSecondaryFile;
    property MediaVolume: Integer read FMediaVolume write FMediaVolume;
    property MediaMuting: Boolean read FMediaMuting write FMediaMuting;
    property MetaSettings: TAHMMetaValueList read FMetaSettings;
    procedure ResetDefaultState;
    procedure LoadState;
    procedure SaveState;
    procedure SaveAsXML(Lines: TStrings);
  end;

implementation

uses SysUtils, TagNames, XMLTags, ErrorCodes, ApplicationManager, Logging;


constructor TAHMPersistenceManager.Create;
begin
  inherited Create;

  // Create meta value list to hold meta settings
  FMetaSettings := TAHMMetaValueList.Create;

  // Initialise default state values
  ResetDefaultState;
end;

destructor TAHMPersistenceManager.Destroy;
begin
  FMetaSettings.FreeWithContents;

  inherited;
end;

procedure TAHMPersistenceManager.ResetDefaultState;
begin
  // Set default values for state
  FPrimaryFolder := '';
  FPrimaryFile := '';
  FSecondaryFolder := '';
  FSecondaryFolder := '';
  FMediaVolume := DEF_MEDIA_VOLUME;
  FMediaMuting := DEF_MEDIA_MUTING;
  FMetaSettings.ClearObjects;
end;

procedure TAHMPersistenceManager.LoadState;
var
  State: TStringList;
begin
  // First set default values for state
  ResetDefaultState;

  // Parse XML to populate custom state values
  ParseXML(ApplicationManagerInstance.ConfigPath);

  // Log our state settings for support purposes
  State := TStringList.Create;
  try
    State.Add('mediate state settings are as follows:');
    SaveAsXML(State);
    LogInfo(State);
  finally
    State.Free;
  end;
end;

procedure TAHMPersistenceManager.SaveState;
var
  State: TStringList;
begin
  State := TStringList.Create;
  try
    SaveAsXML(State);
    State.SaveToFile(ApplicationManagerInstance.ConfigPath + STATE_FILENAME);
  finally
    State.Free;
  end;
end;

function TAHMPersistenceManager.ParseXML(const Filepath: String): Boolean;
var
  RootNode, NextNode: TAHMXMLNode;
begin
  // Default result - problem loading state file
  Result := False;

  // Don't bother trying to parse XML file if its missing
  if not FileExists(FilePath + STATE_FILENAME) then Exit;

  FHelper := TAHMXMLHelper.Create(Filepath + STATE_FILENAME);
  try
    // Ignore preamble - we're looking for a ClientPersistence node
    if not FHelper.FindRootElement(RootNode, TAG_APP_STATE) then
      LogParsingError(XML_PRS_STATE_MISSING_START_TAG);

    // What nodes do we have here?
    NextNode := nil;
    while FHelper.NextElement(RootNode, NextNode) do
    begin
      if FHelper.CurrentElement = TAG_PRIMARY_FOLDER then
        FPrimaryFolder := FHelper.GetValue
      else if FHelper.CurrentElement = TAG_PRIMARY_FILE then
        FPrimaryFile := FHelper.GetValue
      else if FHelper.CurrentElement = TAG_SECONDARY_FOLDER then
        FSecondaryFolder := FHelper.GetValue
      else if FHelper.CurrentElement = TAG_SECONDARY_FILE then
        FSecondaryFile := FHelper.GetValue
      else if FHelper.CurrentElement = TAG_MEDIA_VOLUME then
        FMediaVolume := StrToIntDef(FHelper.GetValue, FMediaVolume)
      else if FHelper.CurrentElement = TAG_MEDIA_MUTING then
        FMediaMuting := StrToBool(FHelper.GetValue)
      else if FHelper.CurrentElement = TAG_META_INFO then
        FMetaSettings.ParseFromXML(FHelper)
      else
        LogParsingError(XML_PRS_STATE_FOUND_UNKNOWN_CONTENT_TAG);
    end;

    // All is well, parsed state file successfully
    Result := True;
  finally
    FHelper.Free;
  end;
end;

procedure TAHMPersistenceManager.SaveAsXML(Lines: TStrings);
begin
  Lines.Add(XML_PREAMBLE);
  Lines.Add(BeginTag(TAG_APP_STATE));
  Lines.Add(TABS[1] + BeginTag(TAG_PRIMARY_FOLDER) + EncodeXMLValue(FPrimaryFolder) + EndTag(TAG_PRIMARY_FOLDER));
  Lines.Add(TABS[1] + BeginTag(TAG_PRIMARY_FILE) + EncodeXMLValue(FPrimaryFile) + EndTag(TAG_PRIMARY_FILE));
  Lines.Add(TABS[1] + BeginTag(TAG_SECONDARY_FOLDER) + EncodeXMLValue(FSecondaryFolder) + EndTag(TAG_SECONDARY_FOLDER));
  Lines.Add(TABS[1] + BeginTag(TAG_SECONDARY_FILE) + EncodeXMLValue(FSecondaryFile) + EndTag(TAG_SECONDARY_FILE));
  Lines.Add(TABS[1] + BeginTag(TAG_MEDIA_VOLUME) + IntToStr(FMediaVolume) + EndTag(TAG_MEDIA_VOLUME));
  Lines.Add(TABS[1] + BeginTag(TAG_MEDIA_MUTING) + BoolToStr(FMediaMuting) + EndTag(TAG_MEDIA_MUTING));
  FMetaSettings.SaveAsXML(Lines);
  Lines.Add(EndTag(TAG_APP_STATE));
end;

procedure TAHMPersistenceManager.LogParsingError(const sErrorCode: String);
begin
  // Log error silently but there's no need to throw an exception
  LogWarn('Encountered error whilst parsing Persistence XML: ' + sErrorCode);
end;


end.
